package atack.tesis.kelluntekun.controllers;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;

import org.vaadin.dialogs.ConfirmDialog;

import atack.tesis.kelluntekun.KelluntekunApplication;
import atack.tesis.kelluntekun.domain.Carpeta;
import atack.tesis.kelluntekun.domain.Etiqueta;
import atack.tesis.kelluntekun.domain.Snippet;
import atack.tesis.kelluntekun.domain.Usuario;
import atack.tesis.kelluntekun.enums.GenCaption;
import atack.tesis.kelluntekun.enums.OpcSnippets;
import atack.tesis.kelluntekun.ui.componentes.AddFolder;
import atack.tesis.kelluntekun.ui.componentes.SearchResultWindow;
import atack.tesis.kelluntekun.ui.componentes.codeInfoView;
import atack.tesis.kelluntekun.ui.componentes.codesTable;
import atack.tesis.kelluntekun.ui.componentes.sideLeftBar;
import atack.tesis.kelluntekun.ui.componentes.utils.UiUtils;

import com.vaadin.addon.jpacontainer.JPAContainer;
import com.vaadin.addon.jpacontainer.JPAContainerFactory;
import com.vaadin.addon.jpacontainer.util.DefaultQueryModifierDelegate;
import com.vaadin.data.Property;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.data.Container.Filter;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.util.filter.Compare;
import com.vaadin.data.util.filter.Like;
import com.vaadin.event.DataBoundTransferable;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.event.dd.DropHandler;
import com.vaadin.event.dd.acceptcriteria.AcceptAll;
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Label;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.TableDragMode;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Tree.TreeDragMode;
import com.vaadin.ui.Tree.TreeTargetDetails;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.VerticalSplitPanel;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.themes.Reindeer;
import com.vaadin.ui.Button;

/**
 * @author marza
 *
 */

public class mainUserHandlerView extends VerticalLayout{
	private static final long serialVersionUID = 1L;
	
	private sideLeftBar slb;
	private codesTable ct;
	private codeInfoView civ;
	private Window modalWinAddSnippet;
	private AddFolder addFolderSubWin; 
	
	private Label titulo;
	private TextField tfSearch;
	private ComboBox cbSearch;
	private Button btSearch;
	private Button btBusquedaAvanzada;
	
	
	private VerticalSplitPanel vertSplit;
	private HorizontalSplitPanel horSplit;
	private HorizontalLayout hlyPanelControl;
	private HorizontalLayout hlySearch;
	
	private Long idSelectedFolder = Long.parseLong("0");
	private Long idSelectedSnippet = Long.parseLong("0");
	
	private Usuario actualUser;
	private JPAContainer<Carpeta> carpetas;
	private JPAContainer<Snippet> snippets;
	private JPAContainer<Snippet> snippetsSearch;
	private JPAContainer<Etiqueta> etiquetas;
	private Filter filtroPorUsuario;
	private Filter filtroEtiquetas;
	
	public static final String CONFIRMACION_CARPETAS_01 = "¿Estás seguro de querer borrar la Carpeta '";
	public static final String CONFIRMACION_CARPETAS_02 = "' y todo su contenido?";
	public static final String CONFIRMACION_SNIPPETS="¿Estás seguro de querer borrar el Snippet ";
	public static final String MOVER_SNIPPET_01 = "¿Estás seguro de querer mover el Snippet '";
	public static final String MOVER_SNIPPET_02 = "' a la Carpeta '";
	
	private static final List<String> opSearch = Arrays.asList(new String[] {
            "Título", "Descripción", "Etiquetas"});
	
	/**
	 * Construye el controlador que maneka la vista principal de usuario.
	 */
	public mainUserHandlerView(){
		this.setMargin(false);
		this.setSpacing(false);
		this.setWidth("100%");
		this.setHeight("100%");
		
		actualUser = (Usuario) KelluntekunApplication.getInstance().getUser();
		filtroPorUsuario = new Compare.Equal("usuario", actualUser);
		
		buildVertSplit();				
		buildPanelControl();
		buildHorSplit();
			
		vertSplit.addComponent(hlyPanelControl);
		vertSplit.addComponent(horSplit);
		
        addComponent(vertSplit);
	}
	
	/**
	 * Construye el VerticalSplitPanel que divide el header de la aplicación.
	 */
	private void buildVertSplit(){
		vertSplit = new VerticalSplitPanel();
		vertSplit.setHeight("100%");
		vertSplit.setWidth("100%");
		vertSplit.setSplitPosition(40, Sizeable.UNITS_PIXELS);
		vertSplit.setLocked(true);
		vertSplit.setStyleName(Reindeer.SPLITPANEL_SMALL);
	}
	
	/**
	 * Construye dento de hlyPanelControl el header de la aplicacion. 
	 * (titulo de la aplicación , barra de busqueda, acceso a datos de la cuenta.) 
	 */
	private void  buildPanelControl(){
		
		hlyPanelControl = new HorizontalLayout();
		hlyPanelControl.setWidth("100%");
		hlyPanelControl.setHeight("100%");
		hlyPanelControl.setSpacing(false);
		hlyPanelControl.setMargin(false);
		hlyPanelControl.setStyleName(Reindeer.LAYOUT_BLACK);

		titulo = new Label("<h1>Kelluntekun</h1>",Label.CONTENT_XHTML);
		titulo.setWidth(null);
		titulo.setHeight(null);
		hlyPanelControl.addComponent(titulo);
		hlyPanelControl.setComponentAlignment(titulo, Alignment.TOP_LEFT);
		
		buildSearchLayout();
		addListenerSearchLayout();
		hlyPanelControl.addComponent(hlySearch);
		hlyPanelControl.setComponentAlignment(hlySearch, Alignment.MIDDLE_CENTER);
		
		MenuBar menubar = new MenuBar();
		MenuBar.MenuItem view = menubar.addItem(actualUser.getNick(),
                new ThemeResource("../runo/icons/16/user.png"), null);
		//TODO editar Datos Usuario.
//		view.addItem("Editar Datos", menuCommand);
		view.addSeparator();
	    view.addItem("Cerrar Sesión", menuCommand);
	    hlyPanelControl.addComponent(menubar);
	    hlyPanelControl.setComponentAlignment(menubar, Alignment.TOP_RIGHT);
	        
	}
	
	/**
	 * Construye la separación entre la barra que muestra las carpetas del usuario (sideLeftBar)
	 * con la clase codesTable donde se mostrarán los snippets de cada carpeta y el contenido de los snippets.
	 */
	private void buildHorSplit(){   
		horSplit = new HorizontalSplitPanel();
		horSplit.setHeight("100%");
		horSplit.setWidth("100%");
		horSplit.setSplitPosition(150, Sizeable.UNITS_PIXELS);
		
		slb = new sideLeftBar();
		slb.setMargin(false);
		
		carpetas = JPAContainerFactory.make(Carpeta.class,KelluntekunApplication.PERSISTENCE_UNIT);
		carpetas.addContainerFilter(filtroPorUsuario);
		
		slb.getFoldersTree().setContainerDataSource(carpetas);
		slb.getFoldersTree().setItemCaptionPropertyId("nombre");
		slb.getFoldersTree().setItemIconPropertyId("folderIcon");
		addListenersSideLeftBar();
		horSplit.addComponent(slb);
		
		
		ct = new codesTable();
		addListenersMenuCodesTable();
		horSplit.addComponent(ct);
		
		civ = new codeInfoView();
	}
	
	/**
	 * Construye el Textfield y el botón de búsqueda en el 'panel de control'
	 */
	private void buildSearchLayout() {
		hlySearch = new HorizontalLayout();
		hlySearch.setWidth(null);
		hlySearch.setHeight(null);
		hlySearch.setSpacing(false);
		hlySearch.setMargin(false);
//		hlySearch.setStyleName(Reindeer.LAYOUT_WHITE);
		
		tfSearch = new TextField();
		tfSearch.setInputPrompt("Búsqueda de Snippets...");
		tfSearch.setNullRepresentation("");
		tfSearch.setRequired(true);
		tfSearch.setWidth("150px");
		tfSearch.setImmediate(true);
//		tfSearch.setStyleName(Reindeer.LAYOUT_WHITE);
		hlySearch.addComponent(tfSearch);
		
		cbSearch = new ComboBox(null, opSearch);
		cbSearch.setNullSelectionAllowed(false);
		cbSearch.setInputPrompt("Criterio...");
//		cbSearch.select("titulo");
		cbSearch.setImmediate(true);
		cbSearch.setRequired(true);
		cbSearch.setWidth("90px");
		hlySearch.addComponent(cbSearch);
		
		btSearch = new Button(">");
		btSearch.setWidth(null);
		btSearch.setStyleName(Reindeer.BUTTON_DEFAULT);
		hlySearch.addComponent(btSearch);
		
		btBusquedaAvanzada = new Button("Búsqueda Avanzada");
		btBusquedaAvanzada.setWidth(null);
		btBusquedaAvanzada.setStyleName(Reindeer.BUTTON_DEFAULT);
		hlySearch.addComponent(btBusquedaAvanzada);
		
	}
	
	/**
	 * Agrega el listener para la búsqueda de snippets.
	 */
	private void addListenerSearchLayout(){
		
		btSearch.addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				if (tfSearch.isValid()&&cbSearch.isValid()){
					
					buildSnippetsSearchContainer();
					addFiltroBusquedaSimple();
					
					if (snippetsSearch.size()>=1&&!snippetsSearch.getFilters().isEmpty()){
						SearchResultWindow srw = new SearchResultWindow(snippetsSearch);
						getWindow().addWindow(srw);
					}
					else{
						getWindow().showNotification(UiUtils.getWarningNotification("<center>Tu Búsqueda no arroja resultados</center>", ""));
						clearSearchFields();
					}
				}
				else{
					getWindow().showNotification(UiUtils.getWarningNotification("<center>Debes introducir texto de búsqueda y seleccionar un criterio</center>", ""));
				}
			}
		});
		
		btBusquedaAvanzada.addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				SearchResultWindow srw = new SearchResultWindow();
				getWindow().addWindow(srw);
			}
		});
	}
	
	/**
	 * Construye el JPAContainer para la busqueda de Snippets.
	 */
	private void buildSnippetsSearchContainer(){
		snippetsSearch = JPAContainerFactory.make(Snippet.class,KelluntekunApplication.PERSISTENCE_UNIT);
		snippetsSearch.removeAllContainerFilters();
		snippetsSearch.setReadOnly(true);
		snippetsSearch.setQueryModifierDelegate(new DefaultQueryModifierDelegate(){
			private static final long serialVersionUID = 1L;
			@Override
            public void queryWillBeBuilt(CriteriaBuilder criteriaBuilder, CriteriaQuery<?> query){
                query.distinct(true);
            }
        });
	}
	
	/**
	 *Agrega el Filtro correspondiente según el usuario haya seleccionado para la búsqueda simple. 
	 */
	private void addFiltroBusquedaSimple(){
		
		if(cbSearch.getValue().toString().equals(opSearch.get(0))){
			//SEARCH TITULO
			Filter fLikeTitulo = new Like("titulo", "%"+tfSearch.getValue().toString()+"%", false);
			snippetsSearch.addContainerFilter(fLikeTitulo);
		}
		if(cbSearch.getValue().toString().equals(opSearch.get(1))){
			//SEARCH DESCRICPCION
			Filter fLikeDescripcion = new Like("descripcion", "%"+tfSearch.getValue().toString()+"%", false);
			snippetsSearch.addContainerFilter(fLikeDescripcion);
		}
		if(cbSearch.getValue().toString().equals(opSearch.get(2))){
			//SEARCH ETIQUETAS
			Etiqueta temp = getEtiquetaFromBD(tfSearch.getValue().toString());
			if(temp!=null){
				Filter ftags = new Compare.Equal("etiquetas",temp);
				snippetsSearch.addContainerFilter(ftags);
			}
		}
	}
	
	/**
	 * Limpia los campos de búsqueda simple.
	 */
	private void clearSearchFields(){
		tfSearch.setValue(null);
		cbSearch.setValue(null);
	}
	
	/**
	 * Agrega Listeners necesario para que la barra donde se muestran las carpetas actualice la tabla de snippets.
	 * así como también los botones que permiten agregar y borrar carpetas.
	 * también dropHandler.
	 * 
	 */
	private void addListenersSideLeftBar(){
		
		slb.getFoldersTree().addListener(new Property.ValueChangeListener(){
			private static final long serialVersionUID = 1L;
			public void valueChange(ValueChangeEvent event){
				if(event.getProperty().getValue() != null){
					ct.removeRightComponent();//Remueve civ (codeInfoView)
					idSelectedFolder =(Long) slb.getFoldersTree().getValue();
					rebuildTcodesAndAddListeners();
					idSelectedSnippet= Long.parseLong("0");
		        }
			}
		});
		
		slb.getBtAddFolder().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				addFolderSubWin = new AddFolder();
				addListenersAddFolderSubWin();
				getWindow().addWindow(addFolderSubWin);
			}
		});
		
		slb.getBtDelFolder().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				if(idSelectedFolder!=0){
					
					String Carpeta = slb.getFoldersTree().getItemCaption(idSelectedFolder);
					ConfirmDialog.show(getWindow(), "Borrar Carpeta", CONFIRMACION_CARPETAS_01+Carpeta+CONFIRMACION_CARPETAS_02, "Confirmar", "Cancelar",
						new ConfirmDialog.Listener(){
							private static final long serialVersionUID = 1L;
							public void onClose(ConfirmDialog dialog){
								if (dialog.isConfirmed()){
									carpetas.removeItem(idSelectedFolder);
									idSelectedFolder=(long) 0;
									rebuildTcodesAndAddListeners();
								}
							}
						});
				}
				else{
					getWindow().showNotification("Debes seleccionar una carpeta.");
				}
			}
		});
		
		slb.getFoldersTree().setDragMode(TreeDragMode.NONE);
		
		slb.getFoldersTree().setDropHandler(new DropHandler(){
			private static final long serialVersionUID = 1L;

			@Override
			public AcceptCriterion getAcceptCriterion(){
				return AcceptAll.get();
			}
			
			@Override
			public void drop(DragAndDropEvent event){
				// Wrapper for the object that is dragged
                DataBoundTransferable t = (DataBoundTransferable) event.getTransferable();
                TreeTargetDetails target = (TreeTargetDetails) event.getTargetDetails();
                
                // Get ids of the dragged item and the target item
                final Snippet draggedSnippet = snippets.getItem(t.getData("itemId")).getEntity();
                final Long targetFolderId=(Long) target.getItemIdOver();                

                if(!targetFolderId.equals(draggedSnippet.getCarpeta().getId())){
                //Si se está moviendo el snippet a una carpeta diferente updatea snippet y recargo la tabla.
                	String targetFolderName = slb.getFoldersTree().getItemCaption(targetFolderId);
                	
					ConfirmDialog.show(getWindow(), "Mover Carpeta", MOVER_SNIPPET_01+draggedSnippet.getTitulo()+MOVER_SNIPPET_02+targetFolderName+"'", "Confirmar", "Cancelar",
						new ConfirmDialog.Listener(){
							private static final long serialVersionUID = 1L;
							public void onClose(ConfirmDialog dialog){
								if (dialog.isConfirmed()){
									draggedSnippet.setCarpeta(carpetas.getItem(targetFolderId).getEntity());
				                	updateSnippetfolder(draggedSnippet);
				                	ct.removeRightComponent();//Remueve civ (codeInfoView)
				                	rebuildTcodesAndAddListeners();
				                	idSelectedSnippet= Long.parseLong("0");
								}
							}
						});
				}
                else{
                	getWindow().showNotification(UiUtils.getWarningNotification("El Snippet ya pertenece a la Carpeta", " "));
				}
			}
		});
		
	}
	
	/**
	 * Reconstruye la tabla donde se muestran los snippets cada vez que se cambia la carpeta.
	 * depende de 'idSelectedFolder'
	 */
	private void rebuildTcodesAndAddListeners(){
		ct.buildTableCodes();
		ct.gettCodes().setDragMode(TableDragMode.ROW);
		if (idSelectedFolder!=0){
			Carpeta c = carpetas.getItem(idSelectedFolder).getEntity();
			
			snippets = JPAContainerFactory.make(Snippet.class,KelluntekunApplication.PERSISTENCE_UNIT);
			snippets.addContainerFilter(filtroPorUsuario);
			
			Filter filtroPorCarpeta = new Compare.Equal("carpeta", c);
			snippets.addContainerFilter(filtroPorCarpeta);
			ct.gettCodes().setContainerDataSource(snippets);
			ct.gettCodes().setVisibleColumns(new String[]{"titulo"});
			ct.gettCodes().setColumnHeader("titulo", "Snippets");
			
		}
		ct.gettCodes().addListener(new Table.ValueChangeListener(){
			private static final long serialVersionUID = 1L;
			
			public void valueChange(ValueChangeEvent event){
				if(event.getProperty().getValue()!=null){
					
					idSelectedSnippet =(Long) event.getProperty().getValue();
					
					Snippet selectedSnippet = snippets.getItem(idSelectedSnippet).getEntity();
					civ = new codeInfoView();
					//TODO cargar etiquetas correctamente.
					civ.setSnippet(selectedSnippet);
					addCodeInfoViewListeners();
					ct.setRightComponent(civ);
				}
				else{
					idSelectedSnippet= Long.parseLong("0");
				}
            }
        });
		
	}
	
	/**
	 * Agrega Los listeners a los botones de la vista de informacion de los snippets (clase codeInfoView)
	 */
	private void addCodeInfoViewListeners(){
		
		civ.getBtEdit().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			
			public void buttonClick(ClickEvent event){
				if(civ.getBtEdit().getCaption()==OpcSnippets.EDITAR.toString()){
					//pasa codeInfoVew a "modo edición"
					civ.setEditMode();
					civ.setButtonsCaptions(OpcSnippets.GUARDAR.toString(), GenCaption.CANCELAR);
					
				}else if(civ.getBtEdit().getCaption()==OpcSnippets.GUARDAR.toString()){
					//Updatea un Snippet y vuelve codeInfoView a "modo lectura"
					updateSnippet(civ.getSnippetEditado());
					civ.setReadOnlyMode();
					civ.setButtonsCaptions(OpcSnippets.EDITAR.toString(), GenCaption.ELIMINAR);
				}
			}
		});
		
		civ.getBtEliminar().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				
				if(civ.getBtEliminar().getCaption()==GenCaption.ELIMINAR){
					
					ConfirmDialog.show(getWindow(), "Borrar Snippet",
						CONFIRMACION_SNIPPETS+"'"+civ.getSnippet().getTitulo()+"' ?" , "Confirmar", "Cancelar",
						new ConfirmDialog.Listener(){
							private static final long serialVersionUID = 1L;
							
							public void onClose(ConfirmDialog dialog){
								if (dialog.isConfirmed()){
									removeSnippet(civ.getSnippet().getId());
								}
							}
						});
					
				}
				else if (civ.getBtEliminar().getCaption()==GenCaption.CANCELAR){
					//Recargar snippet.
					Snippet selectedSnippet = snippets.getItem(civ.getSnippet().getId()).getEntity();
					civ.setSnippet(selectedSnippet);
					civ.setButtonsCaptions(OpcSnippets.EDITAR.toString(), GenCaption.ELIMINAR);
				}
			}
		});
	}
	
	/**
	 * Agrega los listeners a los botones sobre la tabla que muestra los Snippets de codigo
	 */
	private void addListenersMenuCodesTable(){
		
		ct.getBtAddSnippet().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				if(idSelectedFolder!=0){
					buildModalWinAddSnippet();
				}
				else{
					getWindow().showNotification("Debes Seleccionar una carpeta.");
				}
				
			}
		});
		
		ct.getBtDelSnippet().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			
			public void buttonClick(ClickEvent event){
			
				if(idSelectedSnippet==0){
					getWindow().showNotification("Debes seleccionar un snippet.");
				}
				else{
					String snippet = ct.gettCodes().getContainerProperty(ct.gettCodes().getValue(), "titulo").toString();
					
					ConfirmDialog.show(getWindow(), "Borrar Snippet",
						CONFIRMACION_SNIPPETS+"'"+snippet+"' ?" , "Confirmar", "Cancelar",
						new ConfirmDialog.Listener(){
							private static final long serialVersionUID = 1L;
							
							public void onClose(ConfirmDialog dialog){
								if (dialog.isConfirmed()){
									removeSnippet((Long) ct.gettCodes().getValue());
								}
							}
						});
				}
			}
		});
	}
	
	
	/**
	 * Construye SubWindow que se despliega para agregar un nuevo snippet.
	 */
	private void buildModalWinAddSnippet(){
		//podría ser una clase aparte. 
		modalWinAddSnippet = new Window(OpcSnippets.AGREGAR.toString());
		modalWinAddSnippet.setModal(true);
		modalWinAddSnippet.setHeight("100%");
		modalWinAddSnippet.setWidth("65%");
		modalWinAddSnippet.setClosable(false);
		
		final codeInfoView civAddSnippet = new codeInfoView();
		civAddSnippet.setEditMode();
		civAddSnippet.setButtonsCaptions(OpcSnippets.GUARDAR.toString(), GenCaption.CANCELAR);
		
		civAddSnippet.getBtEdit().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				
				if(civAddSnippet.isValid()){
					
					Snippet newSnippet =civAddSnippet.getNewSnippet();
					
					//conjunto de etiquetas definitivas.
					if (newSnippet.getEtiquetas()!=null) {
						newSnippet.setEtiquetas(getEtiquetasDefinitivas(newSnippet.getEtiquetas()));
					}
					//la carpeta en la cual será agregado el snippet.
					Carpeta c = carpetas.getItem(idSelectedFolder).getEntity();
					
					newSnippet.setCarpeta(c);
					newSnippet.setUsuario(actualUser);
					snippets.addEntity(newSnippet);
					snippets.commit();
					carpetas.refresh();
					
					getWindow().removeWindow(modalWinAddSnippet);
					getWindow().showNotification(UiUtils.getTrayNotification("El Snippet ha sido creado."));
				}
				else{
					getWindow().showNotification(
							UiUtils.getWarningNotification("<center>Debes llenar correctamente los campos<center>", ""));
				}
				
			}
		});
		
		civAddSnippet.getBtEliminar().addListener(new Button.ClickListener(){
			//Cancela la Creación de un Snippet.
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				getWindow().removeWindow(modalWinAddSnippet);
			}
		});
		
		
		modalWinAddSnippet.setContent(civAddSnippet);
		getWindow().addWindow(modalWinAddSnippet);
	}
	
	/**
	 * Agrega los Listeners a la clase AddFolder que es la que despliega una subWindow 
	 * cuando se desea agregar una nueva carpeta.
	 */
	private void addListenersAddFolderSubWin(){
		
		addFolderSubWin.getBtCrearCarpeta().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				
				if(addFolderSubWin.isValid()){
					Carpeta c = addFolderSubWin.getCarpeta();
					c.setUsuario(actualUser);
					carpetas.addEntity(c);
					carpetas.commit();
					carpetas.refresh();
					getWindow().removeWindow(addFolderSubWin);
					getWindow().showNotification(UiUtils.getTrayNotification("La Carpeta ha sido creada."));
				}
				else{
					getWindow().showNotification(
							UiUtils.getWarningNotification("<center>Debes llenar correctamente los campos<center>", ""));
				}
				
			}
		});
		
		addFolderSubWin.getBtCancelar().addListener(new Button.ClickListener(){
			private static final long serialVersionUID = 1L;
			public void buttonClick(ClickEvent event){
				getWindow().removeWindow(addFolderSubWin);
			}
		});
	}
	
	/**
	 * Updatea un snippet que ha sido editado. 
	 * 
	 * <b>Nota:</b> el ID del snippet debe tener un valor valido.
	 * @param s. 
	 * 				el Snippet que va a ser updateado.
	 */
	private void updateSnippet(Snippet s){
		snippets.getItem(s.getId()).getItemProperty("titulo").setValue(s.getTitulo());
		snippets.getItem(s.getId()).getItemProperty("codigo").setValue(s.getCodigo());
		snippets.getItem(s.getId()).getItemProperty("descripcion").setValue(s.getDescripcion());
		snippets.getItem(s.getId()).getItemProperty("lenguaje").setValue(s.getLenguaje());
		snippets.getItem(s.getId()).getItemProperty("etiquetas").setValue(getEtiquetasDefinitivas(s.getEtiquetas()));
		
	}
	
	private void updateSnippetfolder(Snippet s){
		snippets.getItem(s.getId()).getItemProperty("carpeta").setValue(s.getCarpeta());
	}
	
	/**
	 * Realiza la validación de un conjunto de etiquetas contra la base de datos
	 * el objetivo es rescatar las etiquetas que ya existen en la BD para que
	 * no haya duplicidad en estas.
	 * @return Conjunto de etiquetas 'Definitivas'
	 */
	private Set<Etiqueta> getEtiquetasDefinitivas(Set<Etiqueta> candidatas){
		etiquetas = JPAContainerFactory.make(Etiqueta.class, KelluntekunApplication.PERSISTENCE_UNIT);
		
		Set<Etiqueta> tagsDefinitivas = new HashSet<Etiqueta>();
		
		for(Etiqueta e : candidatas){
			etiquetas.removeAllContainerFilters();
			filtroEtiquetas = new Compare.Equal("etiqueta", e.getEtiqueta());
			etiquetas.addContainerFilter(filtroEtiquetas);
			if(etiquetas.size()>=1){
				tagsDefinitivas.add(etiquetas.getItem(etiquetas.firstItemId()).getEntity());
			}
			else{
				tagsDefinitivas.add(e);
			}
		}
		return tagsDefinitivas;
	}
	
	/**
	 * Verifica si una etiqueta en particular exsite en la BD si es así la retorna.
	 * @param tag
	 * @return la entidad etiqueta o nulo si no está.
	 */
	private Etiqueta getEtiquetaFromBD(String tag){
		JPAContainer<Etiqueta> tempTags =  JPAContainerFactory.make(Etiqueta.class, KelluntekunApplication.PERSISTENCE_UNIT);
		Filter filtroTags= new Compare.Equal("etiqueta",tag);
		tempTags.addContainerFilter(filtroTags);
		
		if (tempTags.size()>=1){
			return tempTags.getItem(tempTags.firstItemId()).getEntity();
		}
		else{
			return null;
		}
	}
	
	/**
	 * Se encarga de remover del sistema el Snippet correspondiende al id recibido
	 * @param idSnippet
	 */
	private void removeSnippet(Long idSnippet){
		snippets.removeItem(idSnippet);
		ct.removeRightComponent();//Remueve civ (codeInfoView)
		idSelectedSnippet= Long.parseLong("0");
		getWindow().showNotification("<center>Snippet Eliminado.</center><br>",
				" ",Notification.TYPE_TRAY_NOTIFICATION,true);
		
	}
	
	@SuppressWarnings("unused")
	private String getDebugLine(){
		return "################################################################################" +
				"################################DEBUG:  ";
	}
	
	private Command menuCommand = new Command() {
		private static final long serialVersionUID = 1L;
		public void menuSelected(MenuItem selectedItem) {
			if (selectedItem.getText().equals("Cerrar Sesión")){
				KelluntekunApplication.getInstance().close();
			}
		}
	};
}